package main

import (
	"database/sql"
	"github.com/gin-gonic/gin"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"log"
	"net/http"
)

type Order struct {
	OrderId           int64 `gorm:"primaryKey"`
	AccumulativeTotal float64
	Version           int64
}

func (Order) TableName() string {
	return "t_order"
}

// 乐观锁 代码
func main() {
	//建立mysql连接
	dsn := "root:mWwdsqw1s2x3x*@tcp(mysql3:3306)/mytest?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Println("mysql数据库连接失败,", err.Error())
		return
	}
	//创建gin路由
	r := gin.Default()
	r.GET("/update", func(c *gin.Context) {
		//设置读已提交隔离级别
		var opt sql.TxOptions
		opt.Isolation = sql.LevelReadCommitted
		opt.ReadOnly = false
		//开启事务
		tx := db.Begin(&opt)
		var orderBefore Order
		//读取版本号
		tx.Raw("select order_id, accumulative_total, version from t_order where order_id = ?", 1).Scan(&orderBefore)
		//尝试更新
		affected := tx.Exec("update t_order set accumulative_total = ?, version = ? where order_id = ? and version = ?",
			orderBefore.AccumulativeTotal+1.0, orderBefore.Version+1,
			1, orderBefore.Version).RowsAffected
		log.Println("更新结果: ", affected)
		for affected != 1 { //更新失败，数据被其他事务更改了
			//重新读取版本号
			tx.Raw("select order_id, accumulative_total, version from t_order where order_id = ?", 1).Scan(&orderBefore)
			//重新尝试更新
			affected = tx.Exec("update t_order set accumulative_total = ?, version = ? where order_id = ? and version = ?",
				orderBefore.AccumulativeTotal+1.0, orderBefore.Version+1,
				1, orderBefore.Version).RowsAffected
			log.Println("更新结果: ", affected)
		}
		//更新成功了，提交
		tx.Commit()
		c.JSON(http.StatusOK, gin.H{
			"message": "ok",
		})
	})
	r.Run(":8080") // 监听并在 0.0.0.0:8080 上启动服务
}
